package com.strp.mptcp.controller;

import com.strp.mptcp.DAO.entity.FileUploadRecord;
import com.strp.mptcp.DAO.mapper.FileUploadRecordRepository;
import com.strp.mptcp.common.MPTCPMetrics;
import com.strp.mptcp.config.MPTCPConfig;
import com.strp.mptcp.socket.MultipathSocket;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Controller
@RequiredArgsConstructor
public class UploadController {
    private final RestTemplate restTemplate;
    private final FileUploadRecordRepository recordRepository;
    private final MPTCPMetrics metrics;
    private final MPTCPConfig mptcpConfig;

    // 存储正在进行的传输
    private final Map<String, MultipathSocket> activeTransfers = new ConcurrentHashMap<>();

    private static final String INITIATE_URL = "http://server.com:8080/upload/initiate";

    /**
     * 注入 RestTemplate Bean
     */
    @Configuration
    static class RestConfig {
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }



    /**
     * 开始新的文件上传
     */
    @PostMapping("/upload/send")
    public ResponseEntity<UploadResponse> sendViaMptcp(@RequestParam("file") MultipartFile file) {
        try {
            // 1. 验证文件
            if (file.isEmpty()) {
                return ResponseEntity.badRequest().body(new UploadResponse("File is empty"));
            }
            if (file.getSize() > mptcpConfig.getChunk().getSize() * 1024L) { // 使用配置的数据块大小作为文件大小限制
                return ResponseEntity.badRequest().body(new UploadResponse("File too large"));
            }

            File uploadDir = new File(mptcpConfig.getStorage().getUploadDir());
            File tempDir = new File(mptcpConfig.getStorage().getTempDir());
            if (!uploadDir.exists()) {
                uploadDir.mkdir();
            }
            if (!tempDir.exists()) {
                tempDir.mkdir();
            }

            // 2. 创建临时文件
            File tempFile = File.createTempFile("upload-", file.getOriginalFilename());
            file.transferTo(tempFile);

            // 3. 计算文件哈希
            String fileHash = calculateHash(tempFile);

            // 4. 检查是否存在断点
            long offset = checkFileStatus(fileHash, tempFile);

            // 5. 创建传输ID
            String transferId = fileHash;

            // 6. 初始化 MPTCP 连接
            List<SocketAddress> serverAddresses = mptcpConfig.getServer().getAddresses().stream()
                    .map(addr -> new InetSocketAddress(addr.getHost(), addr.getPort()))
                    .collect(Collectors.toList());

            MultipathSocket mptcpSocket = new MultipathSocket(
                    serverAddresses,
                    metrics,
                    mptcpConfig.getChunk().getSize(),
                    mptcpConfig.getChunk().getMaxRetries(),
                    mptcpConfig.getTimeout().getConnection(),
                    mptcpConfig.getTimeout().getRead(),
                    mptcpConfig.getTimeout().getWrite()
            );

            activeTransfers.put(transferId, mptcpSocket);

            // 7. 开始传输
            File targetFile = new File(uploadDir, file.getOriginalFilename());
            mptcpSocket.resumeFromOffset(tempFile, offset, targetFile);

            updateFileRecord(fileHash, file.getOriginalFilename(), file.getSize(), offset);

            return ResponseEntity.ok(new UploadResponse(transferId, offset));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new UploadResponse("Upload failed: " + e.getMessage()));
        }
    }

    /**
     * 获取上传进度
     */
    @GetMapping("/upload/progress/{transferId}")
    public ResponseEntity<ProgressResponse> getProgress(@PathVariable String transferId) {
        MultipathSocket socket = activeTransfers.get(transferId);
        if (socket == null) {
            return ResponseEntity.notFound().build();
        }

        double progress = socket.getTransferProgress(transferId);
        Map<Integer, MPTCPMetrics.SubflowStats> subflowStats = new ConcurrentHashMap<>();

        // 获取每个子流的统计信息
        List<SocketAddress> serverAddresses = mptcpConfig.getServer().getAddresses().stream()
                .map(addr -> new InetSocketAddress(addr.getHost(), addr.getPort()))
                .collect(Collectors.toList());

        for (int i = 0; i < serverAddresses.size(); i++) {
            subflowStats.put(i, socket.getSubflowStats(i));
        }

        return ResponseEntity.ok(new ProgressResponse(progress, subflowStats));
    }

    /**
     * 取消上传
     */
    @PostMapping("/upload/cancel/{transferId}")
    public ResponseEntity<Void> cancelUpload(@PathVariable String transferId) {
        MultipathSocket socket = activeTransfers.remove(transferId);
        if (socket != null) {
            socket.close();
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }

    /**
     * 恢复上传
     */
    @PostMapping("/upload/resume/{transferId}")
    public ResponseEntity<UploadResponse> resumeUpload(@PathVariable String transferId) {
        try {
            // 1. 获取文件记录
            Optional<FileUploadRecord> record = recordRepository.findByFileHash(transferId);
            if (record.isEmpty()) {
                return ResponseEntity.notFound().build();
            }

            // 2. 获取临时文件
            File tempFile = new File(System.getProperty("java.io.tmpdir"),
                    "upload-" + record.get().getFileName());
            if (!tempFile.exists()) {
                return ResponseEntity.badRequest()
                        .body(new UploadResponse("Original file not found"));
            }

            // 3. 创建新的 MPTCP 连接
            List<SocketAddress> serverAddresses = mptcpConfig.getServer().getAddresses().stream()
                    .map(addr -> new InetSocketAddress(addr.getHost(), addr.getPort()))
                    .collect(Collectors.toList());

            MultipathSocket mptcpSocket = new MultipathSocket(
                    serverAddresses,
                    metrics,
                    mptcpConfig.getChunk().getSize(),
                    mptcpConfig.getChunk().getMaxRetries(),
                    mptcpConfig.getTimeout().getConnection(),
                    mptcpConfig.getTimeout().getRead(),
                    mptcpConfig.getTimeout().getWrite()
            );

            activeTransfers.put(transferId, mptcpSocket);

            // 4. 从断点继续
            File uploadDir = new File(mptcpConfig.getStorage().getUploadDir());
            if (!uploadDir.exists()) {
                uploadDir.mkdir();
            }
            File targetFile = new File(uploadDir, record.get().getFileName());
            mptcpSocket.resumeFromOffset(tempFile, record.get().getOffset(), targetFile);


            return ResponseEntity.ok(new UploadResponse(transferId, record.get().getOffset()));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new UploadResponse("Resume failed: " + e.getMessage()));
        }
    }

    /**
     * 根据文件 Hash 查询数据库，返回已完成偏移；若不存在，则新建记录并返回0
     */
    private long checkFileStatus(String fileHash, File file) {
        Optional<FileUploadRecord> opt = recordRepository.findByFileHash(fileHash);
        if (opt.isPresent()) {
            return opt.get().getOffset();
        } else {
            // 新建记录，初始偏移为0
            FileUploadRecord rec = new FileUploadRecord();
            rec.setFileHash(fileHash);
            rec.setFileName(file.getName());
            rec.setFileSize(file.length());
            rec.setOffset(0L);
            rec.setStatus(FileUploadRecord.UploadStatus.PENDING);
            recordRepository.save(rec);
            return 0L;
        }
    }

    /**
     * 计算文件 Hash（例如 MD5）
     */
    private String calculateHash(File file) throws IOException {
        return org.apache.commons.codec.digest.DigestUtils.md5Hex(
                java.nio.file.Files.readAllBytes(file.toPath())
        );
    }

    private void updateFileRecord(String fileHash, String fileName, long fileSize, long offset) {
        FileUploadRecord record = recordRepository.findByFileHash(fileHash)
                .orElse(new FileUploadRecord());
        record.setFileHash(fileHash);
        record.setFileName(fileName);
        record.setFileSize(fileSize);
        record.setOffset(offset);
        record.setStatus(FileUploadRecord.UploadStatus.COMPLETED);
        recordRepository.save(record);
    }

    // DTOs
    @lombok.Data
    static class UploadResponse {
        private final String transferId;
        private final long offset;
        private final String error;

        public UploadResponse(String transferId, long offset) {
            this.transferId = transferId;
            this.offset = offset;
            this.error = null;
        }

        public UploadResponse(String error) {
            this.transferId = null;
            this.offset = 0;
            this.error = error;
        }
    }

    @lombok.Data
    static class ProgressResponse {
        private final double progress;
        private final Map<Integer, MPTCPMetrics.SubflowStats> subflowStats;
    }
}
